/*
 * Diego da Rocha Borges
 * Otávio Zabaleta
 */

#ifndef SYMBOL_TABLE_H
#define	SYMBOL_TABLE_H

#define SYMBOL_UNDEFINED 0
#define SYMBOL_LIT_INTEGER 1
#define SYMBOL_LIT_TRUE 3
#define SYMBOL_LIT_FALSE 4
#define SYMBOL_LIT_CHAR 5
#define SYMBOL_LIT_STRING 6

#define SYMBOL_IDENTIFIER 7
#define SYMBOL_VAR_DEC 8
#define SYMBOL_VEC_DEC 9
#define SYMBOL_FUNC_DEC 10
#define SYMBOL_FUNC_CALL 11
#define SYMBOL_VAR_ASSIGN 12
#define SYMBOL_VEC_ASSIGN 13
#define SYMBOL_FUNC_DEC_PARAM 14
#define SYMBOL_FUNC_CALL_PARAM 15
#define SYMBOL_INT_TYPE 16
#define SYMBOL_BYTE_TYPE 17


// This value must be a PRIME one!!
#define TABLE_SIZE 911

/*
 * Table entry structure. Holds the information about an entry.
 * TODO Does the token information is needed here??
 */
typedef struct hash_entry {
   char* lexeme;

   // tell us if the identifier is a var, vector, function
   int type;

   // the identifier type
   // at the moment it can be an int or byte.
   int dataType;
   
   int line_num;
   struct ast* ast_declaration_node;

}HASH_ENTRY;

/*
 * Implements a linked list to hold the symbol table entries
 */
typedef struct hash_node {
   HASH_ENTRY* data;
   struct hash_node* next;
}HASH_NODE;

/*
 * Symbol Table type definition.
 * <p>
 * A Symbol Table is basiclly a vector of pointers to table_entry_node elements.
 * Each table_entry_node holds the data information about a token/lexeme.
 * </p>
 */
typedef struct hash_table {
    HASH_NODE* entries[TABLE_SIZE];
}HASH_TABLE;

HASH_TABLE* table;

/**
 * Initializes the symbol table.
 * <p>
 * For each entry on table, this entry is setted to NULL.
 * </p>
 *
 * @param table a pointer to the table that need to be initialized.
 */
void hash_init(HASH_TABLE* table);

/**
 * Calculates the hash address for a character sequence.
 *
 * @param text lexeme used to generate a hash address releted to the symbol table.
 * @return the address for the lexeme in the symbol table.
 */
int hash_address(char *lexeme);

/**
 * Inserts a new entry to a symbol table.
 * <p>
 * If the lexeme already exists in the symbol table, a reference to the table entry
 * is returned, otherwise, a new entry is created and a reference to this new entry is
 * returned.
 * </p>
 *
 * @param table a pointer to the symbol table which will receive the new entry.
 * @param lexeme the lexeme to be inserted in the table of symbols.
 * @param type the type of the token (if it is a literal or an identifier for example)
 * @param line_num the line number where the lexeme is defined
 * @return a pointer to the entry in the symbol table for the inserted lexeme.
 */
HASH_NODE* hash_insert_entry(HASH_TABLE* table, char* lexeme, int type, int line_num);

/**
 * Look up a symbol table entry by it's lexeme information.
 * 
 * @param table a ready only copy of the table to look up the entry.
 * @param lexeme the lexeme to be looked up in the symbol table.
 * @param type the lexeme type (identifier, literal...)
 * @return a pointer to the entry of the symbol table.
 */
HASH_NODE* hash_lookup(HASH_TABLE table, char* lexeme, int type);

/**
 * Prints the symbol table in the shell.
 * 
 * @param table a ready only copy of the table.
 * @return the entries count of the table.
 */
void hash_print(HASH_TABLE table);

/**
 * Creates a new table_entry_node using a lexeme and it's token as information for
 * the table_entry data of the node.
 *
 * @param lexeme a lexeme
 * @param type the type of the token (if it is a literal or an identifier for example)
 * @param line_num the line number where the lexeme is defined
 * @return a new entry node in the symbol table.
 */
HASH_NODE* hash_create_hash_node(char* lexeme, int type, int line_num);

/**
 * Create an indentifier in hash table to be used as a bin operation result field
 * @param dataType the var type [SYMBOL_INT_TYPE | SYMBOL_BYTE_TYPE]
 * @return A hash reference
 */
HASH_NODE* make_result_var(int dataType);

/**
 * Create an indentifier in hash table to be used as an assembler label for an
 * operation like if-then-else, while, operations that need labels...
 * @return A hash reference
 */
HASH_NODE* make_label(void);

#endif	/* SYMBOL_TABLE_H */

